
#include <stdio.h>
#include <stdlib.h>
#include "double_list.h"

struct d_list_node {
    struct d_list_node *next;
    struct d_list_node **pprev;
    void *data;
};

#if 0
struct d_list_head {
    struct d_list_node *first;
    DListCmpFunc 	cmp;
    DListDestroyData	destroy;
};
#endif


#if defined _D_LIST_VER4_
#define DLIST_RET_OK	 	 0
#define DLIST_RET_FAIL  	-1
#define DLIST_RET_INVALID_PARAMS	-2

#define return_if_fail(p) if (!(p)) 	\
	{ printf("[%s]:[%d]: Error: "#p" failed! \n",	\
		__func__, __LINE__); return; }

#define return_val_if_fail(p, ret) if (!(p)) 	\
	{ printf("[%s]:[%d]: Error: "#p" failed! \n",	\
		__func__, __LINE__); return(ret); }

#define JA_DEBUG(fmt...) printf("[%s][%d]: %s", __func__, __LINE__, fmt)


DListRet init_list(DList *head, DListCmpFunc cmp,
	DListDestroyData destroy, DListMultiThreadLockCreate create)
{
    DListRet ret;
    do {
    if (NULL == head) {
	JA_DEBUG("Invalid parameters!\n");
	ret = DLIST_RET_INVALID_PARAMS;
	break;
    }

    if (NULL != create) {
	if (NULL == (head->lock = create())) {
	    JA_DEBUG("Create muti-thread list error!\n");
	    ret = DLIST_RET_FAIL;
	    break;
	}
    }
    else {
	head->lock = NULL;
    }

    head->first = NULL;
    head->cmp = cmp;
    head->destroy = destroy;

    ret =  DLIST_RET_OK;

    } while (0);

    if (NULL != head->lock) {
	head->lock->unlock(head->lock);
    }

    return ret;
}

DListRet find_node(DList *head, void *data, void *result)
{
    if (NULL == head || NULL == data)
    {
	JA_DEBUG("Invalid parameters\n");
	return DLIST_RET_INVALID_PARAMS;
    }

    if (NULL != head->lock) {
	head->lock->lock(head->lock);
    }
    result = NULL;
    DNode *node = head->first;
    for(node; NULL != node; node = node->next) {
	if (!head->cmp(node->data, data)) {
	    result = node->data;
	    break;
	}
    }

    if (NULL != head->lock) {
	head->lock->unlock(head->lock);
    }

    return DLIST_RET_OK;
}

DListRet append_to_list(DList *head, void *data)
{
    DNode *first = NULL;
    DNode *node	 = NULL;
    DListRet ret = DLIST_RET_OK;

    if (NULL == head || NULL == data)
    {
	JA_DEBUG("Invalid parameters!\n");
	return DLIST_RET_INVALID_PARAMS;
    }

    if (NULL != head->lock) {
	head->lock->lock(head->lock);
    }

    do {
    first = head->first;
    node = (DNode *)malloc(sizeof(DNode));
    if (NULL == node)
    {
	JA_DEBUG("Malloc error\n");
	ret = DLIST_RET_FAIL;
	break;
    }
    node->data = data;

    node->next = first;
    if (NULL != first)
    {
	first->pprev = &node->next;
    }
    head->first = node;
    node->pprev = &head->first;
    } while (0);

    if (NULL != head->lock) {
	head->lock->unlock(head->lock);
    }

    return ret;
}

static inline DListRet delete_node(DNode *node)
{
    if (NULL == node)
    {
	JA_DEBUG("Invalid parameters\n");
	return DLIST_RET_FAIL;
    }

    DNode *next = node->next;
    DNode **pprev = node->pprev;

    *pprev = next;
    if (NULL != next)
    {
	next->pprev = pprev;
    }

    return DLIST_RET_OK;
}

static inline DListRet add_node(DNode *node)
{
    if (NULL == node)
    {
	JA_DEBUG("Invalid parameters\n");
	return DLIST_RET_FAIL;
    }

    DNode *next = node->next;
    DNode **pprev = node->pprev;

    if (NULL != next)
    {
	next->pprev = pprev;
    }
    *pprev = next;

    return DLIST_RET_OK;
}

DListRet remove_dup_node(DList *head, void *data)
{
    DNode *temp;
    if (NULL == head || NULL == data)
    {
	JA_DEBUG("Invalid parameters\n");
	return DLIST_RET_INVALID_PARAMS;
    }

    if (NULL != head->lock) {
	head->lock->lock(head->lock);
    }

    DNode *node = head->first;
    while (NULL != node)
    {
	if (!head->cmp(node->data, data))
	{
	    temp = node->next;
	    delete_node(node);
	    head->destroy(node->data);
	    free(node);
	    node = temp;
	    continue;
	}
	node = node->next;
    }

    if (NULL != head->lock) {
	head->lock->unlock(head->lock);
    }
    
    return DLIST_RET_OK;
}

DListRet remove_node(DList *head, void *data)
{
    if (NULL == head || NULL == data)
    {
	JA_DEBUG("Invalid parameters\n");
	return DLIST_RET_INVALID_PARAMS;
    }

    if (NULL != head->lock) {
	head->lock->lock(head->lock);
    }

    DNode *node = head->first;
    for(node; NULL != node; node = node->next)
    {
	if (!head->cmp(node->data, data))
	{
	    delete_node(node);
	    head->destroy(node->data);
	    free(node);
	}
    }

    if (NULL != head->lock) {
	head->lock->unlock(head->lock);
    }
    
    return DLIST_RET_OK;
}

DListRet destroy_list(DList *head)
{
    int i = 0;
    if (NULL == head)
    {
	JA_DEBUG("Invalid parameters!\n");
	return DLIST_RET_INVALID_PARAMS;
    }

    if (NULL != head->lock) {
	head->lock->lock(head->lock);
    }

    DNode *node = head->first;
    for(node; NULL != node; node = head->first)
    {
	delete_node(node);
	if (node->data != NULL)
	    head->destroy(node->data);
	free(node);
    }

    if (NULL != head->lock) {
	head->lock->unlock(head->lock);
    }

    return DLIST_RET_OK;
}

DListRet list_for_each(DList *head, DListVisitFunc func, void *ctx)
{
    DListRet ret = DLIST_RET_OK;

    if (NULL == head || NULL == func)
    {
	JA_DEBUG("Invalid parameters\n");
	return DLIST_RET_INVALID_PARAMS;
    }

    if (NULL != head->lock) {
	head->lock->lock(head->lock);
    }

    DNode *node = head->first;
    for (node; NULL != node; node = node->next)
    {
	if (func(node->data, ctx))
	{
	    JA_DEBUG("Modifid error\n");
	    ret = DLIST_RET_FAIL;
	    goto done;
	}
    }

done:
    if (NULL != head->lock) {
	head->lock->unlock(head->lock);
    }

    return ret;
}

#endif
